<?php

namespace App\Http\Controllers\Admin;

use App\Caches\ManagerCache;
use App\Constants\WechatConstant;
use App\Exceptions\ApiException;
use App\Http\Controllers\Controller;
use App\Models\Manager;
use App\Models\ManagerOauthRelation;
use App\Services\IpAddrService;
use App\Services\NoticeDingDingService;
use App\Services\SmsService;
use App\Services\Wechat\OfficialAccountService;
use App\Traits\ThrottlesLogins;
use Illuminate\Http\Request;

class LoginController extends Controller
{
    use ThrottlesLogins;

    /**
     * @var int 失败后锁定时间
     */
    protected $decayMinutes = 10;

    /**
     * 配合 ThrottlesLogins 使用
     * @return string
     */
    protected function username(): string
    {
        return 'username';
    }

    /**
     * 常规账号密码登录
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     * @throws \Illuminate\Validation\ValidationException
     */
    public function authenticate(Request $request)
    {
        if (config("admin.enable_login") === false) {
            return responseException("本系统已停止服务(1)");
        }


        $request->validate([
            'username' => 'required',
            'password' => 'required',
            'code' => 'required',
        ]);

        // 尝试次数超出
        if ($this->hasTooManyLoginAttempts($request)) {
            NoticeDingDingService::sendText("警告: {$request->ip()} 多次尝试使用 {$request->username} 进行登录, 已锁定 {$this->decayMinutes} 分钟");
            $this->sendLockoutResponse($request);
        }

        $failedFunc = function(string $message) use ($request) {
            // 记录登录次数
            $this->incrementLoginAttempts($request);
            return responseException($message);
        };

        // 校验验证码
        $manager = Manager::whereUsername($request->username)->first();

        if (!$manager || !password_verify($request->password, $manager->password)) return $failedFunc(__('auth.password_not_match'));

        if (!$manager->mobile) return $failedFunc(__('auth.user_mobile_not_bind'));

        try {
            SmsService::checkVerifyCode($manager->mobile, $request->code);
        } catch (ApiException $e) {
            info(__METHOD__, [$e->getMessage(), $manager->mobile, $request->code]);
            return $failedFunc($e->getMessage());
        }


        // if (!Auth::attempt($credentials)) {
        //     $this->incrementLoginAttempts($request);
        //     return responseException(__('auth.failed'));
        // }

        return $this->loginSuccess($request, $manager);
    }

    /**
     * 登录成功
     * @param Request $request
     * @param Manager $manager
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    private function loginSuccess(Request $request, Manager $manager)
    {
        if (app()->isProduction() && config("admin.enable_login") && IpAddrService::isWarning(getClientIp(), IpAddrService::ACTION_LOGIN_ADMIN)) {
            NoticeDingDingService::sendText("IP登录ADMIN被ban, Username: {$manager->username}, Truename: {$manager->name}, Ip: ". getClientIp());
            return responseException('本系统已停止服务');
        }

        if ($manager->is_forbidden && (int)$manager->is_forbidden === Manager::MANAGER_FORBIDDEN) {
            return responseException('该账号已被禁用，请联系管理员');
        }

        $manager->tokens()->delete();
        $token = $manager->createToken('admin', ['*'])->plainTextToken;
        // Auth::setUser($manager);
        // $request->session()->regenerate(true);

        $manager->lasttime = now();
        $manager->lastip = getClientIp();
        $manager->save();

        return responseData($token);
    }

    /**
     * 生成 登录二维码
     * @param Request $request
     * @param OfficialAccountService $service
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function getQrcode(Request $request, OfficialAccountService $service)
    {
        $request->validate([
            'client_id' => 'required',
            'channel' => 'required',
        ]);

        $url = '';
        $ttl = 600;
        if ($request->channel === 'wechat') {
            $qrcodeInfo = ['client_id' => $request->client_id,];
            $url = $service->getQrcodeTemporary(WechatConstant::EVENT_ADMIN_LOGIN, $qrcodeInfo, $ttl);
        }

        return responseData([
            'channel' => $request->channel,
            'url' => $url,
            'ttl' => $ttl,
        ]);
    }

    /**
     * 登录二维码接收
     * @param string $channel
     * @param string $openid
     * @param array $qrcodeInfo
     * @throws \Psr\SimpleCache\InvalidArgumentException
     */
    public function loginQrcodeReceive(string $channel, string $openid, array $qrcodeInfo)
    {
        ManagerCache::setOpenid($qrcodeInfo['client_id'], $channel, $openid);
    }

    /**
     * 二维码查询 有值直接登录
     * @param Request $request
     * @return false|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    public function qrcodeQuery(Request $request)
    {

        if (config("admin.enable_login") === false) {
            return responseException("本系统已停止服务(1)");
        }

        $openid = ManagerCache::getOpenid($request->client_id, $request->channel);
        if ($openid) {
            $managerOauthRelation = ManagerOauthRelation::whereChannel($request->channel)->whereOpenid($openid)->has('manager')->first();
            if (!$managerOauthRelation) return false;

            return $this->loginSuccess($request, $managerOauthRelation->manager);
        }
        return false;
    }

    /**
     * 发送验证码
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     * @throws \App\Exceptions\ApiException
     * @throws \Illuminate\Validation\ValidationException
     */
    public function sendCode(Request $request)
    {
        $request->validate([
            'username' => 'required',
        ]);

        // 尝试次数超出
        if ($this->hasTooManyLoginAttempts($request)) {
            $this->sendLockoutResponse($request);
        }

        $mobile = Manager::whereUsername($request->username)->value('mobile');
        if (!$mobile) {
            // 记录失败次数
            $this->incrementLoginAttempts($request);
            return responseException(__('auth.user_mobile_not_bind'));
        }

        list($mobile, $code, $expiredAt) = SmsService::sendVerifyCode($mobile);

        return responseMessage(__('api.sms_request_success'));
    }
}
